package com.xjm_cloud_admin.util;

import com.madgag.gif.fmsware.AnimatedGifEncoder;
import com.madgag.gif.fmsware.GifDecoder;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;

public class ImageCompressionUtils {

    public static boolean compressImage(String destination, MultipartFile file) throws Exception {
        byte[] d = convertInputStreamToByteArray(file.getInputStream());
        byte[] compress = compressGif(d, 0.4f);
        if (compress.length < d.length) {
            //压缩后体积是减小的，才保存
            writeByteArrayToFile(new File(destination), compress);
            return true;
        } else {
            return false;
        }
    }

    public static byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024]; // 缓冲区大小可以根据需要调整
        int bytesRead;

        // 读取InputStream中的数据到缓冲区，然后写入ByteArrayOutputStream
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, bytesRead);
        }

        // 将ByteArrayOutputStream中的数据转换为byte数组
        return byteArrayOutputStream.toByteArray();
    }

    public static void writeByteArrayToFile(File file, byte[] data) throws IOException {
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(data);
        fos.close();
    }


    public static boolean isImage(String originalFilename) {
        // 检查文件扩展名是否为常见的图片格式
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        return fileExtension.equals("jpg") ||
                fileExtension.equals("jpeg") ||
                fileExtension.equals("png") ||
                fileExtension.equals("gif");
    }


    public byte[] readFileToByteArray(File file) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        FileInputStream fis = new FileInputStream(file);
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = fis.read(buffer)) != -1) {
            baos.write(buffer, 0, len);
        }
        fis.close();
        return baos.toByteArray();
    }

    public static byte[] compressGif(byte[] data, float scale) throws Exception {
        ByteArrayInputStream stream = new ByteArrayInputStream(data);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GifDecoder decoder = new GifDecoder();
        decoder.read(stream);
        int cnt = decoder.getFrameCount();
        //如果只有一帧，直接压缩到20kb
        if (cnt == 1) {
            return compressPicForScale(data, 20, "jpg");
        }
        int width = decoder.getImage().getWidth();
        int height = decoder.getImage().getHeight();
        //缩放倍率
//        width = (int) (width * scale);
//        height = (int) (height * scale);

        AnimatedGifEncoder e = new AnimatedGifEncoder();
        // 设置生成图片大小
        e.setSize(width, height);
        //保存到数组
        e.start(out);
        //重复次数 0表示无限重复 默认不重复
        e.setRepeat(0);
        //进行采样
        BufferedImage[] fs = getFrames(decoder);
        int i = 0;
        int delay = 0;
        for (BufferedImage f : fs) {
            if (fs.length > 1) {
                i++;
                //设置延迟
//                int delay = 100;
//                if (fs.length == 5) {
//                    delay = 200;
//                } else if (fs.length == 4) {
//                    delay = 400;
//                } else {
//                    delay = 600;
//                }
                delay += decoder.getDelay(i);
            }
            BufferedImage image = compressPic(f, scale);
            e.addFrame(image);

        }
        e.finish();
        e.setDelay(delay / fs.length);
        return out.toByteArray();
    }

    private static BufferedImage[] getFrames(GifDecoder decoder) {
        int cnt = decoder.getFrameCount();
        //我这里只采了6帧
        int max = (int) Math.floor((double) cnt / 3);

        BufferedImage[] r = new BufferedImage[cnt - max];
        for (int i = 0; i < cnt - max; i++) {
            r[i] = decoder.getFrame(i);
        }
        return r;

//        if (cnt <= max) {
//
//        } else if (cnt < max * 2) {
//            BufferedImage[] r = new BufferedImage[max + 2];
//            for (int i = 0; i < max + 2; i++) {
//                r[i] = decoder.getFrame(i);
//            }
//            return r;
//        } else {
//            BufferedImage[] r = new BufferedImage[max];
//            int sec = cnt / max;
//            int n = 0;
//            for (int i = 0; i < cnt && n < max; i += sec) {
//                r[n] = decoder.getFrame(i);
//                n++;
//            }
//            return r;
//        }
    }

    public static float getScare(int width, int height) {
        int n = Math.max(width, height);
        float rate;
        //大于450像素
        if (n >= 450) {
            //缩放到450*0.2=90像素
            rate = 0.2f;
        } else if (n >= 400) {
            rate = 0.26f;
        } else if (n >= 300) {
            rate = 0.3f;
        } else if (n >= 200) {
            rate = 0.4f;
        } else if (n >= 100) {
            rate = 0.6f;
        } else if (n >= 80) {
            rate = 0.7f;
        } else {
            rate = 0.8f;
        }
        return rate;
    }

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize, String prefix) throws Exception {
        long d = desFileSize * 1024;
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length <= d) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);

        while (imageBytes.length > d) {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
            BufferedImage read = ImageIO.read(inputStream);
            Thumbnails.of(read)
                    .scale(accuracy)
                    .outputQuality(accuracy)
                    .outputFormat(prefix)
                    .toOutputStream(outputStream);
            imageBytes = outputStream.toByteArray();
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }

    public static BufferedImage compressPic(BufferedImage frame, float scale) throws Exception {
        return Thumbnails.of(frame).outputFormat("jpg").scale(1).outputQuality(scale).asBufferedImage();
    }

}
